﻿/**
 * AESCryptography.cs
 * 
 * 作者：Gates_ice
 * 日期：2012年1月18日
 * 说明：
 * 实现了AES的加密，密钥必须使用256位（32字符），向量必须使用128位（16字符）
 * 代码参考了 http://hi.baidu.com/why99010/blog/item/a40cb24eced5b4ccd1c86ab3.html 实现
 * 
 * 2012-02-08 修改:
 * - 将加密密钥和向量修改为字节数组的形式并对相关的成员和方法进行了更改
 * - 为IEncryptography接口的修改做了调整
 * 
 */

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Security.Cryptography;
using System.IO;

namespace P2PChat.Security.Cryptography
{
    /// <summary>
    /// AES加密的实现
    /// </summary>
    public class AESCryptography : IEncryptography
    {
        /// <summary>
        /// 加密密钥
        /// </summary>
        private byte[] key;
        /// <summary>
        /// 获取加密密钥
        /// </summary>
        public byte[] Key { get { return key; } }
        /// <summary>
        /// 加密向量
        /// </summary>
        private byte[] iV;
        /// <summary>
        /// 获取加密向量
        /// </summary>
        public byte[] IV { get { return iV; } }

        /// <summary>
        /// 使用给定的密钥和向量初始化,当使用中文字符串请注意转换后的位数.
        /// </summary>
        /// <param name="key">加密密钥，256位</param>
        /// <param name="iV">加密向量，128位</param>
        public AESCryptography(string key, string iV)
        {
            byte[] bKey = Encoding.UTF8.GetBytes(key);
            byte[] bIV = Encoding.UTF8.GetBytes(iV);

            if (bKey.Length != 256)
            {
                throw new InvalidKeyException(key);
            }
            if (bIV.Length != 128)
            {
                throw new InvalidVecterException(iV);
            }
            this.key = bKey;
            this.iV = bIV;
        }

        /// <summary>
        /// 使用给定的密钥和向量初始化
        /// </summary>
        /// <param name="key">加密密钥，256字节</param>
        /// <param name="iV">加密向量，128字节</param>
        public AESCryptography(byte[] bKey, byte[] bIV)
        {
            if (bKey.Length != 256)
            {
                throw new InvalidKeyException(bKey);
            }
            if (bIV.Length != 128)
            {
                throw new InvalidVecterException(bIV);
            }
            this.key = bKey;
            this.iV = bIV;
        }

        /// <summary>
        /// 获得某个字符串的密文
        /// </summary>
        /// <param name="plainStr">明文</param>
        /// <returns>密文</returns>
        public string Encrypt(string plainStr)
        {
            byte[] byteArray = Encoding.UTF8.GetBytes(plainStr);

            string encrypt = null;
            Rijndael aes = Rijndael.Create();
            try
            {
                using (MemoryStream mStream = new MemoryStream())
                {
                    using (CryptoStream cStream = new CryptoStream(mStream, aes.CreateEncryptor(key, iV), CryptoStreamMode.Write))
                    {
                        cStream.Write(byteArray, 0, byteArray.Length);
                        cStream.FlushFinalBlock();
                        encrypt = Convert.ToBase64String(mStream.ToArray());
                    }
                }
            }
            catch { }
            finally
            {
                aes.Clear();
            }
            return encrypt;
        }

        /// <summary>
        /// 获得某段加密字符串的原文
        /// </summary>
        /// <param name="encryptedStr">密文</param>
        /// <returns>原文</returns>
        public string Decrypt(string encryptedStr)
        {
            byte[] byteArray = Convert.FromBase64String(encryptedStr);

            string decrypt = null;
            Rijndael aes = Rijndael.Create();
            try
            {
                using (MemoryStream mStream = new MemoryStream())
                {
                    using (CryptoStream cStream = new CryptoStream(mStream, aes.CreateDecryptor(key, iV), CryptoStreamMode.Write))
                    {
                        cStream.Write(byteArray, 0, byteArray.Length);
                        cStream.FlushFinalBlock();
                        decrypt = Encoding.UTF8.GetString(mStream.ToArray());
                    }
                }
            }
            catch { }
            finally
            {
                aes.Clear();
            }

            return decrypt;
        }

        /// <summary>
        /// 对密文进行解密
        /// </summary>
        /// <param name="encryptedStr">密文</param>
        /// <param name="result">明文</param>
        /// <returns>解密是否成功</returns>
        public bool TryDecrypt(string encryptedStr, out string result)
        {
            byte[] byteArray = Convert.FromBase64String(encryptedStr);
            Rijndael aes = Rijndael.Create();
            try
            {
                using (MemoryStream mStream = new MemoryStream())
                {
                    using (CryptoStream cStream = new CryptoStream(mStream, aes.CreateDecryptor(key, iV), CryptoStreamMode.Write))
                    {
                        cStream.Write(byteArray, 0, byteArray.Length);
                        cStream.FlushFinalBlock();
                        result = Encoding.UTF8.GetString(mStream.ToArray());
                    }
                }
            }
            catch (Exception ex) {
                result = null;
                return false;
            }
            finally
            {
                aes.Clear();
            }
            return true;
        }


        public byte[] Encrypt(byte[] plainData)
        {
            Rijndael aes = Rijndael.Create();
            try
            {
                using (MemoryStream mStream = new MemoryStream())
                {
                    using (CryptoStream cStream = new CryptoStream(mStream, aes.CreateEncryptor(key, iV), CryptoStreamMode.Write))
                    {
                        cStream.Write(plainData, 0, plainData.Length);
                        cStream.FlushFinalBlock();
                        return mStream.ToArray();
                    }
                }
            }
            catch (Exception ex)
            {
                throw ex;
            }
            finally
            {
                aes.Clear();
            }
        }

        public byte[] Decrypt(byte[] encryptedData)
        {
            Rijndael aes = Rijndael.Create();
            try
            {
                using (MemoryStream mStream = new MemoryStream())
                {
                    using (CryptoStream cStream = new CryptoStream(mStream, aes.CreateDecryptor(key, iV), CryptoStreamMode.Write))
                    {
                        cStream.Write(encryptedData, 0, encryptedData.Length);
                        cStream.FlushFinalBlock();
                        return mStream.ToArray();
                    }
                }
            }
            catch (Exception ex)
            {
                throw ex;
            }
            finally
            {
                aes.Clear();
            }
        }

        public bool TryDecrypt(byte[] encryptedData, out byte[] result)
        {
            Rijndael aes = Rijndael.Create();
            try
            {
                using (MemoryStream mStream = new MemoryStream())
                {
                    using (CryptoStream cStream = new CryptoStream(mStream, aes.CreateDecryptor(key, iV), CryptoStreamMode.Write))
                    {
                        cStream.Write(encryptedData, 0, encryptedData.Length);
                        cStream.FlushFinalBlock();
                        result = mStream.ToArray();
                    }
                }
            }
            catch (Exception ex)
            {
                result = null;
                return false;
            }
            finally
            {
                aes.Clear();
            }
            return true;
        }
    }
}
